const express = require('express');
const fs = require('fs');
const path = require('path');
const cors = require('cors');
const WebSocket = require('ws');

const app = express();
const PORT = 3000;

// 添加文件锁
const fileLocks = new Map();

// 获取文件锁
const acquireLock = (filePath) => {
    return new Promise((resolve, reject) => {
        if (fileLocks.has(filePath)) {
            reject(new Error('文件正在被其他操作锁定'));
            return;
        }
        fileLocks.set(filePath, true);
        resolve();
    });
};

// 释放文件锁
const releaseLock = (filePath) => {
    fileLocks.delete(filePath);
};

// 配置 CORS
app.use(cors({
    origin: '*', // 允许所有来源访问
    methods: ['GET', 'POST', 'PUT', 'DELETE'], // 允许的 HTTP 方法
    allowedHeaders: ['Content-Type', 'Authorization'] // 允许的请求头
}));

// 设置响应头，支持中文
app.use((req, res, next) => {
  if (req.path.endsWith('.html')) {
    res.header('Content-Type', 'text/html;charset=utf-8');
  } 
  else if (req.path.endsWith('.css')) {
    res.header('Content-Type', 'text/css;charset=utf-8');
  }
  else {
    res.header('Content-Type', 'application/json;charset=utf-8');
  }
  next();
});

app.use(express.json());
app.use(express.urlencoded({ extended: true }));

// 提供静态文件服务
app.use(express.static(path.join(__dirname, 'public'), {
  setHeaders: (res, path) => {
    if (path.endsWith('.html')) {
      res.setHeader('Content-Type', 'text/html;charset=utf-8');
    }
  }
}));

// 数据文件路径
const dataPath = path.join(__dirname, 'data', 'members.json');

// 确保数据目录存在
if (!fs.existsSync(path.join(__dirname, 'data'))) {
  fs.mkdirSync(path.join(__dirname, 'data'));
}

// 读取成员数据
const readMembers = async () => {
    try {
        await acquireLock(dataPath);
        if (!fs.existsSync(dataPath)) {
            return { members: [] };
        }
        const data = fs.readFileSync(dataPath, 'utf8');
        const parsedData = JSON.parse(data);
        // 确保返回的数据格式正确
        return {
            members: Array.isArray(parsedData.members) ? parsedData.members : []
        };
    } catch (error) {
        console.error('读取数据失败:', error);
        return { members: [] };
    } finally {
        releaseLock(dataPath);
    }
};

// 保存成员数据
const saveMembers = async (data) => {
    try {
        await acquireLock(dataPath);
        // 确保保存的数据格式正确
        const dataToSave = {
            members: Array.isArray(data.members) ? data.members : []
        };
        fs.writeFileSync(dataPath, JSON.stringify(dataToSave, null, 2), 'utf8');
    } catch (error) {
        console.error('保存数据失败:', error);
        throw error;
    } finally {
        releaseLock(dataPath);
    }
};

// 创建 WebSocket 服务器
const wss = new WebSocket.Server({ 
    port: 3001,
    clientTracking: true,
    perMessageDeflate: {
        zlibDeflateOptions: {
            chunkSize: 1024,
            memLevel: 7,
            level: 3
        },
        zlibInflateOptions: {
            chunkSize: 10 * 1024
        },
        clientNoContextTakeover: true,
        serverNoContextTakeover: true,
        serverMaxWindowBits: 10,
        concurrencyLimit: 10,
        threshold: 1024
    }
});

// 心跳检测间隔（毫秒）
const HEARTBEAT_INTERVAL = 30000;

// 存储所有连接的客户端
const clients = new Set();

// 优雅关闭处理
const cleanup = () => {
    console.log('正在关闭服务器...');
    // 关闭所有客户端连接
    clients.forEach(client => {
        if (client.readyState === WebSocket.OPEN) {
            client.close(1000, '服务器正在关闭');
        }
    });
    // 关闭 WebSocket 服务器
    wss.close(() => {
        console.log('WebSocket 服务器已关闭');
        process.exit(0);
    });
};

process.on('SIGINT', cleanup);
process.on('SIGTERM', cleanup);

// 处理未捕获的异常
process.on('uncaughtException', (err) => {
    console.error('未捕获的异常:', err);
    cleanup();
});

// 处理未处理的 Promise 拒绝
process.on('unhandledRejection', (reason, promise) => {
    console.error('未处理的 Promise 拒绝:', reason);
    cleanup();
});

wss.on('connection', (ws) => {
    console.log('新的客户端连接');
    clients.add(ws);
    
    // 发送当前数据和在线人数
    readMembers().then(data => {
        ws.send(JSON.stringify({
            type: 'init',
            data: {
                members: Array.isArray(data.members) ? data.members : [],
                onlineCount: clients.size
            }
        }));
    }).catch(error => {
        console.error('发送初始数据失败:', error);
        ws.send(JSON.stringify({
            type: 'init',
            data: { members: [], onlineCount: clients.size }
        }));
    });

    // 广播在线人数更新
    const broadcastOnlineCount = () => {
        const message = JSON.stringify({
            type: 'update',
            data: {
                onlineCount: clients.size
            }
        });
        clients.forEach(client => {
            if (client.readyState === WebSocket.OPEN) {
                client.send(message);
            }
        });
    };
    broadcastOnlineCount();

    // 设置心跳检测
    const heartbeat = setInterval(() => {
        if (ws.readyState === WebSocket.OPEN) {
            try {
                ws.send(JSON.stringify({ type: 'pong' }));
            } catch (error) {
                console.error('发送心跳失败:', error);
                clearInterval(heartbeat);
                ws.terminate();
            }
        }
    }, HEARTBEAT_INTERVAL);

    ws.on('message', (message) => {
        try {
            const data = JSON.parse(message);
            if (data.type === 'ping') {
                // 响应心跳
                ws.send(JSON.stringify({ type: 'pong' }));
            }
        } catch (error) {
            console.error('处理消息错误:', error);
        }
    });

    ws.on('error', (error) => {
        console.error('WebSocket 错误:', error);
        clearInterval(heartbeat);
        clients.delete(ws);
    });

    ws.on('close', () => {
        console.log('客户端断开连接');
        clearInterval(heartbeat);
        clients.delete(ws);
        broadcastOnlineCount();
    });
});

// 广播数据更新
const broadcastUpdate = (data) => {
    const message = JSON.stringify({
        type: 'update',
        data: {
            members: Array.isArray(data.members) ? data.members : []
        }
    });
    
    clients.forEach(client => {
        if (client.readyState === WebSocket.OPEN) {
            try {
                client.send(message);
            } catch (error) {
                console.error('广播消息失败:', error);
                client.terminate();
                clients.delete(client);
            }
        }
    });
};

// 获取所有成员
app.get('/api/members', async (req, res) => {
    try {
        const data = await readMembers();
        res.json(data);
    } catch (error) {
        console.error('获取成员列表失败:', error);
        res.status(500).json({ members: [] });
    }
});

// 添加新成员
app.post('/api/members', async (req, res) => {
    try {
        const data = await readMembers();
        const newMember = {
            id: Date.now(),
            name: req.body.name,
            maxRestDays: req.body.maxRestDays || 6,
            selectedDays: {},
            color: req.body.color || '#409EFF'
        };
        data.members.push(newMember);
        await saveMembers(data);
        broadcastUpdate(data);
        res.json(newMember);
    } catch (error) {
        console.error('添加成员失败:', error);
        res.status(500).json({ error: '添加成员失败' });
    }
});

// 删除成员
app.delete('/api/members/:id', async (req, res) => {
    try {
        const data = await readMembers();
        data.members = data.members.filter(member => member.id !== parseInt(req.params.id));
        await saveMembers(data);
        broadcastUpdate(data);
        res.json({ success: true });
    } catch (error) {
        console.error('删除成员失败:', error);
        res.status(500).json({ error: '删除成员失败' });
    }
});

// 更新成员选休日期
app.put('/api/members/:id/days', async (req, res) => {
    try {
        const data = await readMembers();
        const member = data.members.find(m => m.id === parseInt(req.params.id));
        if (member) {
            const selectedDays = req.body.selectedDays;
            
            // 按月份分组并验证每月的选休天数
            const monthlyDays = {};
            Object.keys(selectedDays).forEach(month => {
                const daysInMonth = selectedDays[month];
                if (daysInMonth.length > member.maxRestDays) {
                    throw new Error(`${month}月份超出最大选休天数限制`);
                }
                monthlyDays[month] = daysInMonth;
            });

            // 检查日期是否被其他成员选中
            const occupiedDays = new Set();
            data.members.forEach(m => {
                if (m.id !== member.id) {
                    Object.values(m.selectedDays).flat().forEach(day => occupiedDays.add(day));
                }
            });

            const hasConflict = Object.values(selectedDays).flat().some(day => occupiedDays.has(day));
            if (hasConflict) {
                return res.status(400).json({ error: '所选日期已被其他成员选中' });
            }

            member.selectedDays = selectedDays;
            await saveMembers(data);
            broadcastUpdate(data);
            res.json(member);
        } else {
            res.status(404).json({ error: '成员不存在' });
        }
    } catch (error) {
        console.error('更新选休日期失败:', error);
        res.status(500).json({ error: error.message || '更新选休日期失败' });
    }
});

// 清空所有选休数据
app.post('/api/clear', async (req, res) => {
    try {
        const data = await readMembers();
        data.members.forEach(member => {
            member.selectedDays = {};
        });
        await saveMembers(data);
        broadcastUpdate(data);
        res.json({ success: true });
    } catch (error) {
        console.error('清空选休数据失败:', error);
        res.status(500).json({ error: '清空选休数据失败' });
    }
});

// 清空当前月份选休数据
app.post('/api/clear-current-month', async (req, res) => {
    try {
        const { year, month } = req.body;
        const yearMonth = `${year}-${String(month + 1).padStart(2, '0')}`;
        const data = await readMembers();
        
        data.members.forEach(member => {
            if (member.selectedDays[yearMonth]) {
                delete member.selectedDays[yearMonth];
            }
        });
        
        await saveMembers(data);
        broadcastUpdate(data);
        res.json({ success: true });
    } catch (error) {
        console.error('清空当前月份选休数据失败:', error);
        res.status(500).json({ error: '清空当前月份选休数据失败' });
    }
});

// 处理所有其他路由，返回 index.html
app.get('*', (req, res) => {
  res.sendFile(path.join(__dirname, 'public', 'index.html'), {
    headers: {
      'Content-Type': 'text/html;charset=utf-8'
    }
  });
});

// 启动服务器
const server = app.listen(PORT, () => {
  console.log(`HTTP 服务器运行在 http://localhost:${PORT}`);
  console.log(`WebSocket 服务器运行在 ws://localhost:3001`);
});

// 处理服务器错误
server.on('error', (error) => {
  if (error.code === 'EADDRINUSE') {
    console.error(`端口 ${PORT} 已被占用，请尝试使用其他端口`);
    process.exit(1);
  } else {
    console.error('服务器错误:', error);
    process.exit(1);
  }
});